﻿using LibNiconico.NiconicoApi.Internal.Http;
using LibNiconico.NiconicoApi.Lives.Constant;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace LibNiconico.NiconicoApi.Lives.Broadcast
{

    /// <summary>
    /// 放送枠作成結果コード
    /// </summary>
    public enum NicoLiveBroadcastResultCode
    {
        /// <summary>
        /// 成功
        /// </summary>
        Succeed,

        /// <summary>
        /// 順番待ち中
        /// </summary>
        Queueing,

        /// <summary>
        /// 順番待ち開始した
        /// </summary>
        QueueStart,

        /// <summary>
        /// 他の放送を予約中
        /// </summary>
        ReservedOtherBroadcast,

        /// <summary>
        /// 放送枠作成失敗
        /// </summary>
        CreateBroadcastFailed,
    }

    /// <summary>
    /// 放送枠作成レスポンス
    /// </summary>
    public class NicoLiveBroadcastCreateResponse
    {


        internal NicoLiveBroadcastCreateResponse(NicoLiveBroadcastResultCode resultCode, string message):this(resultCode,message,null,"",null)
        {
            
        }


        private NicoLiveBroadcastCreateResponse(NicoLiveBroadcastResultCode resultCode, string message, NicoLiveBroadcastableLiveInfo liveInfo, string confirm,NicoLiveBroadcastableLiveInfo otherLiveInfo)
        {
            this.ResultCode = resultCode;
            this.Message = message;
            this.LiveInfo = liveInfo;
            this.Confirm = confirm;
            this.OtherLiveInfo = otherLiveInfo;
        }


        /// <summary>
        /// 放送枠作成が成功したか判定
        /// </summary>
        public bool Succeed
        {
            get
            {
                return this.ResultCode == NicoLiveBroadcastResultCode.Succeed;
            }
        }

        /// <summary>
        /// 作成した生放送情報
        /// </summary>
        public NicoLiveBroadcastableLiveInfo LiveInfo { get; private set; }

        /// <summary>
        /// 待機中か判定
        /// </summary>
        public bool IsQueueing
        {
            get
            {
                return this.ResultCode == NicoLiveBroadcastResultCode.Queueing || this.ResultCode == NicoLiveBroadcastResultCode.QueueStart;
            }
        }


        /// <summary>
        /// すでに作成してある別の生放送情報
        /// </summary>
        public NicoLiveBroadcastableLiveInfo OtherLiveInfo { get; private set; }

        /// <summary>
        /// メッセージ
        /// </summary>
        public string Message { get; private set; }

        /// <summary>
        /// 結果コード
        /// </summary>
        public NicoLiveBroadcastResultCode ResultCode { get; private set; }


        /// <summary>
        /// 確認画面メッセージ
        /// </summary>
        public string Confirm { get; private set; }


        internal static NicoLiveBroadcastCreateResponse Parse(NiconicoHttpResponse<XDocument> response)
        {
            var responseUrlAbsolutePath = response.ResponseUri.AbsolutePath;
            var liveIdRegex = new Regex(NicoLiveConstant.LIVE_ID_FORMAT);
            var match = liveIdRegex.Match(responseUrlAbsolutePath); 

            if (match.Success)
            {
                if (responseUrlAbsolutePath.Contains("watch"))
                {
                    var createResponse = new NicoLiveBroadcastCreateResponse(
                        resultCode: NicoLiveBroadcastResultCode.Succeed,
                        message: "放送枠取得に成功しました");

                    
                    createResponse.LiveInfo = new NicoLiveBroadcastableLiveInfo( match.Value );

                    return createResponse;
                    
                }

                if (responseUrlAbsolutePath.Contains("editstream"))
                {
                    var createResponse = new NicoLiveBroadcastCreateResponse(
                        resultCode: NicoLiveBroadcastResultCode.Queueing,
                        message: "放送枠取得順番待ちです");

                    createResponse.LiveInfo = new NicoLiveBroadcastableLiveInfo( match.Value);
                    createResponse.Confirm = getConfirm(response.Content);
                    return createResponse;

                }


                
            }

            var errorMessageNodes = from node in response.Content.Descendants("li")
                                    where (string)node.Attribute("id") == "error_message"
                                    select node.Value;

            if (errorMessageNodes.Count() > 0)
            {
                var errorMessage = errorMessageNodes.First();

                if (errorMessage.Contains("既にこの時間に予約をしているか") || errorMessage.Contains("順番待ちのユーザーがいるため"))
                {
                    var createResponse = new NicoLiveBroadcastCreateResponse(
                        resultCode: NicoLiveBroadcastResultCode.ReservedOtherBroadcast,
                        message: "別の放送を予約中です");
                        
                    createResponse.OtherLiveInfo = new NicoLiveBroadcastableLiveInfo( liveIdRegex.Match(errorMessage).Value);
                    return createResponse;
                }

                if (errorMessage.Contains("既に順番待ちに並んでいるか"))
                {
                    var createResponse = new NicoLiveBroadcastCreateResponse(
                        resultCode: NicoLiveBroadcastResultCode.Queueing,
                        message: "放送枠取得順番待ちです");

                    createResponse.Confirm = getConfirm(response.Content);

                    return createResponse;
                }

                if (errorMessage.Contains("順番"))
                {
                    var createResponse = new NicoLiveBroadcastCreateResponse(
                        resultCode: NicoLiveBroadcastResultCode.QueueStart,
                        message: "順番待ちを開始しました");

                    return createResponse;
                }
            }


            return new NicoLiveBroadcastCreateResponse(
                resultCode:NicoLiveBroadcastResultCode.CreateBroadcastFailed,
                message:"放送作成に失敗しました");

            


        }


        private static string getConfirm(XDocument document)
        {
            var confirmNodes = from node in document.Descendants("a")
                               where (string)node.Attribute("class") == "txt12" && node.Attribute("onclick") != null && ((string)node.Attribute("onclick")).Contains("ulck")
                               select node.Attribute("onclick").Value;


            if (confirmNodes.Count() > 0)
            {
                var match = Regex.Match(confirmNodes.First(), "ulck_[0-9]+");

                if (match.Success)
                {
                    return match.Value;
                }
            }

            return "";
        }
    }
}
